package api

import (
	"net/http"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	"todo-gin-server/internal/domain/entity"
	"todo-gin-server/internal/infrastructure/persistence"
)

// TodoController 待办事项控制器
type TodoController struct {
	todoRepository persistence.TodoRepositoryImpl
}

// NewTodoController 创建待办事项控制器
func NewTodoController() *TodoController {
	return &TodoController{
		todoRepository: persistence.TodoRepositoryImpl{},
	}
}

// CreateTodoRequest 创建待办事项请求
type CreateTodoRequest struct {
	Title       string     `json:"title" binding:"required"`
	Description string     `json:"description"`
	DueDate     *time.Time `json:"due_date"`
}

// UpdateTodoRequest 更新待办事项请求
type UpdateTodoRequest struct {
	Title       string     `json:"title"`
	Description string     `json:"description"`
	Completed   *bool      `json:"completed"`
	DueDate     *time.Time `json:"due_date"`
}

// GetAllTodos 获取当前用户的所有待办事项
func (c *TodoController) GetAllTodos(ctx *gin.Context) {
	userID, exists := ctx.Get("userID")
	if !exists {
		ctx.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
		return
	}

	todos, err := c.todoRepository.FindByUserID(userID.(uint))
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch todos"})
		return
	}

	ctx.JSON(http.StatusOK, gin.H{
		"message": "Todos fetched successfully",
		"todos":   todos,
	})
}

// GetTodoByID 根据ID获取待办事项
func (c *TodoController) GetTodoByID(ctx *gin.Context) {
	userID, exists := ctx.Get("userID")
	if !exists {
		ctx.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
		return
	}

	todoID, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid todo ID"})
		return
	}

	todo, err := c.todoRepository.FindByID(uint(todoID))
	if err != nil {
		ctx.JSON(http.StatusNotFound, gin.H{"error": "Todo not found"})
		return
	}

	// 验证待办事项是否属于当前用户
	if todo.UserID != userID.(uint) {
		ctx.JSON(http.StatusForbidden, gin.H{"error": "You don't have permission to access this todo"})
		return
	}

	ctx.JSON(http.StatusOK, gin.H{
		"message": "Todo fetched successfully",
		"todo":    todo,
	})
}

// CreateTodo 创建待办事项
func (c *TodoController) CreateTodo(ctx *gin.Context) {
	userID, exists := ctx.Get("userID")
	if !exists {
		ctx.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
		return
	}

	var req CreateTodoRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	todo := &entity.Todo{
		Title:       req.Title,
		Description: req.Description,
		DueDate:     req.DueDate,
		UserID:      userID.(uint),
	}

	if err := c.todoRepository.Create(todo); err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create todo"})
		return
	}

	ctx.JSON(http.StatusCreated, gin.H{
		"message": "Todo created successfully",
		"todo":    todo,
	})
}

// UpdateTodo 更新待办事项
func (c *TodoController) UpdateTodo(ctx *gin.Context) {
	userID, exists := ctx.Get("userID")
	if !exists {
		ctx.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
		return
	}

	todoID, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid todo ID"})
		return
	}

	todo, err := c.todoRepository.FindByID(uint(todoID))
	if err != nil {
		ctx.JSON(http.StatusNotFound, gin.H{"error": "Todo not found"})
		return
	}

	// 验证待办事项是否属于当前用户
	if todo.UserID != userID.(uint) {
		ctx.JSON(http.StatusForbidden, gin.H{"error": "You don't have permission to update this todo"})
		return
	}

	var req UpdateTodoRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// 更新待办事项
	if req.Title != "" {
		todo.Title = req.Title
	}
	if req.Description != "" {
		todo.Description = req.Description
	}
	if req.Completed != nil {
		todo.Completed = *req.Completed
	}
	if req.DueDate != nil {
		todo.DueDate = req.DueDate
	}

	if err := c.todoRepository.Update(todo); err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update todo"})
		return
	}

	ctx.JSON(http.StatusOK, gin.H{
		"message": "Todo updated successfully",
		"todo":    todo,
	})
}

// DeleteTodo 删除待办事项
func (c *TodoController) DeleteTodo(ctx *gin.Context) {
	userID, exists := ctx.Get("userID")
	if !exists {
		ctx.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
		return
	}

	todoID, err := strconv.ParseUint(ctx.Param("id"), 10, 32)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid todo ID"})
		return
	}

	todo, err := c.todoRepository.FindByID(uint(todoID))
	if err != nil {
		ctx.JSON(http.StatusNotFound, gin.H{"error": "Todo not found"})
		return
	}

	// 验证待办事项是否属于当前用户
	if todo.UserID != userID.(uint) {
		ctx.JSON(http.StatusForbidden, gin.H{"error": "You don't have permission to delete this todo"})
		return
	}

	if err := c.todoRepository.Delete(uint(todoID)); err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete todo"})
		return
	}

	ctx.JSON(http.StatusOK, gin.H{
		"message": "Todo deleted successfully",
	})
}